<template>
  <div class="fx-input" :class="[size]" v-bind="$attrs">
    <template v-if="type!=='textarea'">
      <div class="prefix-icon" v-if="prefixIcon!==''&&!$slots.prefix">
        <i class="fs14 iconfont" :class="prefixIcon"/>
      </div>
      <div class="prefix-icon" v-if="$slots.prefix">
        <slot name="prefix"></slot>
      </div>
      <input v-model="inputValue" :type="inputType" :style="{width:`${$attrs.width}px`}"
             @blur="inputBlur" ref="inputDom" @focus="$emit('focus',inputValue)"
             :readonly="$attrs.readonly"
             :disabled="$attrs.disabled" :placeholder="$attrs.placeholder"
             :class="{round,prefix:(prefixIcon===''&&!$slots.prefix),
             suffix:(suffixIcon===''&&!clear&&!password&&!$slots.suffix)}">
      <template v-if="!$slots.suffix">
        <div class="suffix-icon" v-if="clear&&inputValue!==''" @click="clearInputClick">
          <i class="fs12 iconfont icon-multiply_circle"/>
        </div>
        <div class="suffix-icon" v-else-if="password" @click="showHidePasswordClick">
          <i class="fs12 iconfont icon-open-eyes"/>
        </div>
        <div class="suffix-icon" v-else-if="suffixIcon!==''">
          <i class="fs14 iconfont" :class="suffixIcon"/>
        </div>
      </template>
      <div class="suffix-icon" v-else>
        <slot name="suffix"></slot>
      </div>
    </template>
    <div class="textarea" v-else>
      <textarea v-bind="$attrs" :style="{resize:$attrs.resize}"></textarea>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, inject, onMounted, PropType, ref, SetupContext, watch } from 'vue'
import { ComponentSize, componentSizeArr } from '@/base/types'
import { Emitter } from 'mitt'

interface InputProps {
  modelValue: string;
  type: string;
  size: ComponentSize;
  prefixIcon: string;
  suffixIcon: string;
  clear: boolean;
  password: boolean;
  round: boolean;
  autoFocus: boolean;
  debounce: number;
  length: number;
}

export default defineComponent({
  name: 'FInput',
  props: {
    // v-model
    modelValue: {
      type: String as PropType<string>,
      required: true
    },
    // 原生type
    type: {
      type: String as PropType<string>,
      default: 'text'
    },
    // 大小
    size: {
      type: String as PropType<ComponentSize>,
      default: 'default',
      validator (val: ComponentSize): boolean {
        return componentSizeArr.includes(val)
      }
    },
    // 前部icon
    prefixIcon: {
      type: String as PropType<string>,
      default: ''
    },
    // 后部icon
    suffixIcon: {
      type: String as PropType<string>,
      default: ''
    },
    // 清空
    clear: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 显示密码
    password: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 圆角
    round: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 是否自动聚焦
    autoFocus: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    // 防抖动延迟
    debounce: {
      type: Number as PropType<number>,
      default: 0
    },
    // 输入长度限制
    length: {
      type: Number as PropType<number>,
      validator (val: number): boolean {
        return Number.isInteger(val) && val >= 0
      },
      default: 0
    }
  },
  emits: ['update:modelValue', 'input', 'blur', 'focus'],
  setup (props: InputProps, ctx: SetupContext) {
    // 当前输入框内容
    const inputValue = ref<string>(Math.floor(props.length) > 0 ? props.modelValue.slice(0, Math.floor(props.length)) : props.modelValue)
    // input
    const inputDom = ref<HTMLElement | undefined>(undefined)
    // 当前输入框类型
    const inputType = ref<string>(props.type)
    // 接收formItem mitt 监听器
    const formItemMitt = inject<Emitter['emit'] | undefined>('formItemMitt', undefined)
    // 定时器
    let inputTimer: null | ReturnType<typeof setTimeout> = null

    watch(() => props.modelValue, (val: string) => {
      inputValue.value = Math.floor(props.length) > 0 ? val.slice(0, Math.floor(props.length)) : val
    })
    watch(inputValue, (val: string) => {
      val = Math.floor(props.length) > 0 ? val.slice(0, Math.floor(props.length)) : val
      inputValue.value = val
      if (props.debounce <= 0) {
        ctx.emit('update:modelValue', val)
        ctx.emit('input', val)
        return
      }
      inputTimer && clearTimeout(inputTimer)
      inputTimer = setTimeout(() => {
        ctx.emit('update:modelValue', val)
        ctx.emit('input', val)
      }, props.debounce)
    })

    // 清空输入框
    const clearInputClick = (): void => {
      inputValue.value = ''
      if (inputDom.value) inputDom.value.focus()
    }
    // 显示/隐藏输入框
    const showHidePasswordClick = (): void => {
      inputType.value = inputType.value === 'password' ? 'text' : 'password'
    }
    // 失焦
    const inputBlur = (): void => {
      if (formItemMitt) formItemMitt('formItemBlur', inputValue.value)
      ctx.emit('blur', inputValue.value)
    }

    onMounted(() => {
      // 当开启显示密码时 输入框自动转为密码类型
      if (props.password) inputType.value = 'password'
      // 发送当前的数据给formItem
      if (formItemMitt) formItemMitt('formItemValue', inputValue.value)
      // 是否自动聚焦
      setTimeout(() => {
        if (props.autoFocus && inputDom.value) inputDom.value.focus()
      })
    })

    return {
      inputValue,
      inputType,
      inputDom,
      inputBlur,
      clearInputClick,
      showHidePasswordClick
    }
  }
})
</script>
